/*

Copyright 2009 Nicola Dal Pont

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Version ${MAJOR_VERSION}.${MINOR_VERSION}${BETA_MARK} Build ${BUILD_NUMBER}

*/
package com.astoolkit.workflow
{
	import com.astoolkit.workflow.api.*;
	import com.astoolkit.workflow.constant.Feed;
	import com.astoolkit.workflow.constant.Flow;
	import com.astoolkit.workflow.constant.Iterate;
	import com.astoolkit.workflow.constant.TaskStatus;
	import com.astoolkit.workflow.constant.UNDEFINED;
	
	import flash.events.IEventDispatcher;
	
	import mx.collections.IList;
	import mx.core.IFactory;
	
	[Event(
		name="subtaskInitialized",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskPrepared",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskStarted",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskDataSet",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskWarning",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskFault",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskCompleted",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskProgress",
		type="com.astoolkit.workflow.WorkflowEvent")]
	[Event(
		name="subtaskAborted",
		type="com.astoolkit.workflow.WorkflowEvent")]

	public class AbstractWorkflow extends BaseTask implements IWorkflow
	{
		include "../../../../meta/Version.as";
		
		protected var _root : IWorkflow;
		
		protected var _insert : Vector.<Insert>;
		
		protected var _childrenDelegate : IWorkflowDelegate;
		
		protected var _iterate : String = null;
		
		protected var _retain : Boolean = false;
		
		protected var _flow : String = Flow.SERIAL;
		
		protected var _feed : String = Feed.PIPELINE;
		
		
		
		protected static var _retainedWorkflows : Object = [];
		
		protected var _subPipelineData : *;
		
		[ArrayElementType("com.astoolkit.workflow.IWorkflowTask")]
		protected var _processedTasks : Array = []
		
		protected var _nextTaskIndex : int = 0;
		
		protected var _children : Vector.<IWorkflowElement> = new Vector.<IWorkflowElement>();
		
		protected var _tasks : Vector.<IWorkflowTask>;
		
		protected var _contextFactory : IFactory;
		
		protected var _inheritedInserts : Vector.<Insert>;
		
		/*
			Flag used to check whether to clear  dataProvider after complete(). 
			This is necessarey if the data provider is coming from the pipeline
			as dataProvider is only set from the pipeline if dataProvider is null
			at begin() time.
		*/
		protected var _clearDataProviderOnComplete : Boolean;
		
		/**
		 * the data source for this repeater's iteration.
		 */
		[Bindable]
		protected var _dataProvider : IList;
		
		/**
		 * @private
		 */
		protected var _currentDataIndex : int = -1;
		
		//============================ PUBLIC PROPERTIES =============================
		
		/**
		 * When the repeater is running this property contains the item from
		 * dataProvider at currentDataIndex
		 */
		[Bindable]
		public var currentData : *;
		
		/**
		 * Utility property. true if currentDataIndex == 0
		 */
		[Bindable]
		public var processingFirst : Boolean;
		
		/**
		 * Utility property. true if currentDataIndex == dataProvider.length -1
		 */
		[Bindable]
		public var processingLast : Boolean;
		
		public function AbstractWorkflow()
		{
			super();
		}

        [Bindable]
        public function set dataProvider( inValue : IList ) : void
        {
            if( status == TaskStatus.RUNNING )
                return;
            if( inValue )
                _iterate = Iterate.DATA;
            _dataProvider = inValue;
        }
        
        public function get dataProvider() : IList
        {
            return _dataProvider;
        }

		public function get contextFactory():IFactory
		{
			return null;
		}
		
		public function set contextFactory(inFactory:IFactory):void
		{
		}
		
        [Bindable]
        [ArrayElementType("com.astoolkit.workflow.api.IWorkflowElement")]
        public function get children() : Vector.<IWorkflowElement>
        {
            return _children;   
        }
        
        public function set children( inChildren : Vector.<IWorkflowElement> ) : void
        {
            if( _children && _children.length > 0 )
                throw new Error( "Tasks list cannot be overridden" );
			_children = inChildren;
            for each( var child : IWorkflowElement in _children )
                child.parent = this;
        }

        public function set insert(inInsert: Vector.<Insert>):void
		{
			if( _insert )
				throw new Error( "insert cannot be redefined" );
			_insert = inInsert;
		}
		
		public function get insert():Vector.<Insert>
		{
			return _insert;
		}
		
       
        /**
         * he current dataProvider index in a running repeater.
         * Binding is triggered although this property is read-only
         */ 
        [Bindable]
        public function get currentDataIndex() : int
        {
            return _currentDataIndex;
        }
        
        /**
         * @private
         */
        public function set currentDataIndex( inIndex : int ) : void
        {
            //EMPTY SETTER. NEEDED TO ALLOW BINDING
        }
        
		
		public function get flow():String
		{
			return null;
		}
		
		public function set flow(inFlow:String):void
		{
		}

        /**
         * @inheritDoc 
         */
        public function get iterate() : String
        {
            return _iterate;
        }
        
        [Inspectable( enumeration="loop,data")]
        public function set iterate( inIterate: String ) : void
        {
            _iterate = inIterate;
        }		
		
		public function get feed():String
		{
			return null;
		}
		
		public function set feed(inPolicy:String):void
		{
		}
		
		protected function createDelegate() : IWorkflowDelegate
		{
			return null;
		}
		
		protected function setSubtaskPipelineData( inTask : IWorkflowTask ) : void
		{
			if( _subPipelineData == UNDEFINED )
			{
				if( _feed == Feed.PIPELINE )
				{
					_subPipelineData = filteredPipelineData;
				}
				else if( _feed == Feed.CURRENT_DATA )
				{
					_subPipelineData = currentData;
				}
			}
			
			if( inTask.taskOutput == UNDEFINED )
			{
				if( inTask.inlet != null )
				{
					try
					{
						if( Object( inTask ).hasOwnProperty( inTask.inlet ) )
						{
							if( inTask[ inTask.inlet ] is Function )
							{
								var f : Function = inTask[ inTask.inlet ] as Function; 
								f.apply( inTask, [ _subPipelineData ] );
							}
							else
								inTask[ inTask.inlet ] = _subPipelineData;
						}
					}
					catch( e : Error )
					{
						trace( e.getStackTrace() );
						//TODO: failure management;
					}
				}
				inTask.taskInput = _subPipelineData;
			}
		}

		protected function get runtimeTasks() : Vector.<IWorkflowTask>
		{
			if( !_tasks )
				_tasks = GroupUtil.getRuntimeTasks( _children );
			return _tasks;
		}
		/**
         * @private
         */
        protected function nextData() : void
        {
            _subPipelineData = UNDEFINED;
            for each( var task : IWorkflowTask in runtimeTasks )
            {
                task.prepare();
            }
            if( _dataProvider )
            {
                _currentDataIndex ++;
                currentData = dataProvider.getItemAt( _currentDataIndex );
            }
            _nextTaskIndex = 0;
            _processedTasks = [];
        }
		
		override public function cleanUp():void
		{
			super.cleanUp();
			_tasks = null;
		}
		
	}
}